package com.vois.jack.btmgr.classicbase;

import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.media.AudioManager;
import android.os.Build;
import android.os.DeadSystemException;
import android.telephony.TelephonyManager;
import android.util.Log;

import com.vois.jack.btmgr.util.Logger;

import java.lang.reflect.Method;
import java.util.List;

public class BtHelper {
    private Logger logger = Logger.getLogger(BtHelper.class);
    private BluetoothAdapter bluetoothAdapter;
    private BluetoothA2dp bluetoothA2dp;
    private BluetoothHeadset bluetoothHeadset;
    private BluetoothManager bluetoothManager;
    private TelephonyManager telephonyManager;
    private AudioManager audioManager;
    private Context appContext;
    private BtHelperListener listener;
    private static BtHelper instance;
    private boolean isInited;

    private BluetoothProfile.ServiceListener serviceListener = new BluetoothProfile.ServiceListener() {
        @Override
        public void onServiceConnected(int i, BluetoothProfile bluetoothProfile) {
            if (i == BluetoothProfile.HEADSET) {
                logger.d( "onServiceConnected: BluetoothProfile.HEADSET");
                bluetoothHeadset = (BluetoothHeadset)bluetoothProfile;
            }else if (i == BluetoothProfile.A2DP) {
                logger.d( "onServiceConnected: BluetoothProfile.A2DP");
                bluetoothA2dp = (BluetoothA2dp)bluetoothProfile;
            }

            if (bluetoothA2dp != null && bluetoothHeadset != null) {
                if (listener != null) {
                    listener.onInited();
                }
            }
        }

        @Override
        public void onServiceDisconnected(int i) {
            if (i == BluetoothProfile.A2DP) {
                bluetoothA2dp = null;
                logger.d( "onServiceDisconnected: BluetoothProfile.A2DP");
            }else if (i == BluetoothProfile.HEADSET) {
                bluetoothHeadset = null;
                logger.d( "onServiceDisconnected: BluetoothProfile.HEADSET");
            }
        }
    };

    interface BtHelperListener {
        void onInited();
    }

    public static BtHelper getInstance() {
        if (instance == null) {
            instance = new BtHelper();
        }

        return instance;
    }

    void init(Context appContext, BtHelperListener listener) throws IllegalStateException {
        if (!isInited) {
            bluetoothManager = (BluetoothManager) appContext.getSystemService(Context.BLUETOOTH_SERVICE);
            this.appContext = appContext;
            this.listener = listener;

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                if (bluetoothManager != null) {
                    bluetoothAdapter = bluetoothManager.getAdapter();
                }else {
                    throw new IllegalStateException("Can't get BluetoothManager");
                }
            } else {
                bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
            }

            audioManager = (AudioManager) appContext.getSystemService(Context.AUDIO_SERVICE);
            telephonyManager = (TelephonyManager) appContext.getSystemService(Context.TELEPHONY_SERVICE);
            if (bluetoothAdapter != null) {
                bluetoothAdapter.getProfileProxy(appContext, serviceListener, BluetoothProfile.A2DP);
                bluetoothAdapter.getProfileProxy(appContext, serviceListener, BluetoothProfile.HEADSET);
            }
            isInited = true;
        }
    }

    void deInit() {
        if (isInited) {
            if(bluetoothAdapter != null){
                bluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP, bluetoothA2dp);
                bluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET, bluetoothHeadset);
                bluetoothAdapter = null;
            }
            bluetoothA2dp = null;
            bluetoothHeadset = null;
            bluetoothManager = null;
            isInited = false;
        }
    }

    int getBluetoothState() {
        if (isInited) {
            return bluetoothAdapter.getState();
        }

        return BluetoothAdapter.STATE_OFF;
    }

    void connectHeadset(BluetoothDevice device) {
        if (bluetoothHeadset != null && device != null) {
            if (bluetoothHeadset.getConnectionState(device) != BluetoothProfile.STATE_CONNECTING ||
            bluetoothHeadset.getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) {
                Method connectMethod = null;
                try {
                    connectMethod = BluetoothHeadset.class.getMethod("connect", BluetoothDevice.class);
                }catch (NoSuchMethodException e) {
                    e.printStackTrace();
                    return;
                }

                try {
                    connectMethod.invoke(bluetoothHeadset, device);
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    void connectA2DP(BluetoothDevice device) {
        if (bluetoothA2dp != null && device != null) {
            if (bluetoothA2dp.getConnectionState(device) != BluetoothProfile.STATE_CONNECTING ||
            bluetoothA2dp.getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) {
                Method connectMethod = null;
                try {
                    connectMethod = BluetoothA2dp.class.getMethod("connect", BluetoothDevice.class);
                }catch (NoSuchMethodException e) {
                    e.printStackTrace();
                    return;
                }

                try {
                    connectMethod.invoke(bluetoothA2dp, device);
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    void disconnectHeadset(BluetoothDevice device) {
        if (bluetoothHeadset != null && device != null) {
            if (bluetoothHeadset.getConnectionState(device) != BluetoothProfile.STATE_DISCONNECTING ||
            bluetoothHeadset.getConnectionState(device) != BluetoothProfile.STATE_DISCONNECTED) {
                Method disconnectMethod = null;
                try {
                    disconnectMethod = BluetoothHeadset.class.getMethod("disconnect", BluetoothDevice.class);
                }catch (NoSuchMethodException e) {
                    e.printStackTrace();
                    return;
                }

                try {
                    disconnectMethod.invoke(bluetoothHeadset, device);
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    void disconnectA2DP(BluetoothDevice device) {
        if (bluetoothA2dp != null && device != null) {
            if (bluetoothA2dp.getConnectionState(device) != BluetoothProfile.STATE_DISCONNECTING ||
            bluetoothA2dp.getConnectionState(device) != BluetoothProfile.STATE_DISCONNECTED) {
                Method disconnectMethod = null;
                try {
                    disconnectMethod = BluetoothA2dp.class.getMethod("disconnect", BluetoothDevice.class);
                }catch (NoSuchMethodException e) {
                    e.printStackTrace();
                    return;
                }

                try {
                    disconnectMethod.invoke(bluetoothA2dp, device);
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    int getHeadsetState(BluetoothDevice device) {
        if (bluetoothHeadset != null && device != null) {
            return bluetoothHeadset.getConnectionState(device);
        }

        return BluetoothAdapter.STATE_DISCONNECTED;
    }

    int getA2DPState(BluetoothDevice device) {
        if (bluetoothA2dp != null && device != null) {
            return bluetoothA2dp.getConnectionState(device);
        }

        return BluetoothAdapter.STATE_DISCONNECTED;
    }

    List<BluetoothDevice> getConnectedA2dpDevices() {
        if (bluetoothA2dp != null) {
            return bluetoothA2dp.getConnectedDevices();
        }
        return null;
    }

    List<BluetoothDevice> getConnectedHeadsetDevices() {
        if (bluetoothHeadset != null) {
            return bluetoothHeadset.getConnectedDevices();
        }
        return null;
    }

    boolean openAudioSco(int audioMode) {
        if (audioManager.isBluetoothScoAvailableOffCall()) {
            audioManager.stopBluetoothSco();
            audioManager.setBluetoothScoOn(true);
            if (audioMode == AudioManager.MODE_NORMAL || audioMode == AudioManager.MODE_IN_COMMUNICATION) {
                audioManager.setMode(audioMode);
            }else {
                audioManager.setMode(AudioManager.MODE_IN_CALL);
            }

            audioManager.startBluetoothSco();
            return true;
        }

        return false;
    }

    boolean closeAudioSco() {
        if (telephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
            return true;
        }

        audioManager.stopBluetoothSco();
        audioManager.setBluetoothScoOn(false);
        audioManager.setMode(AudioManager.MODE_NORMAL);
        return true;
    }

    boolean isAudioScoOn() {
        boolean isAudioScoOn = false;
        if (audioManager != null) {
            try {
                isAudioScoOn = audioManager.isBluetoothScoOn();
            }catch (Exception e) {
                e.printStackTrace();
                isAudioScoOn = false;
            }
        }

        return isAudioScoOn;
    }

    void cancelDiscovering() {
        if (bluetoothAdapter != null) {
            bluetoothAdapter.cancelDiscovery();
        }
    }

    public int getCurrentToneVolume() {
        if(audioManager != null) {
            return audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
        }

        return 0;
    }

    public int getMaxToneVolume() {
        if(audioManager != null) {
            return audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
        }

        return 0;
    }
}
